Introduction

In an asymmetric algorithm, a JWT token is signed with an Identity Provider’s private key. To verify the signature of the token, one will need to have a matching public key. This post will cover how to use the JWT tool at https://jwt.io/ to verify the signature of an signed Azure AD token (either access or id token).

Note:

  • You should only validate the token intended for your own resource.  Using the technique below to validate the signature of a Microsoft First Party Apps token (for example token audience is for Microsoft Graph resource) may fail.
  • http://jwt.io utility is a 3rd party tool.  We (Microsoft) have no knowledge of how this site utilizes the token information.
  • To see the token claim information, we recommend using the Microsoft utility http://jwt.ms since the site does not cache token information.

Verifying the token signature

  1. Browse to https://jwt.io/ and paste the JWT token into Encoded text box. The tool should automatically detect the token’s signature algorithm (RS256) and displays the token into 3 parts: header, payload, and signature. Note the “kid” field in the header. This is the key id of the certificate used to sign the token

    Scrolling down a little you will see the version of the token (v1 token in this case) and it will say “invalid signature”. This is expected since at this point we have not provided any certificate info for the tool to verify the token signature.

  2. Find the jwks URL info from Azure AD’s OIDC well-known endpoint. Depending upon your token version, use the correct well known endpoint (make sure to supply the correct tenant name in the well known URL):

    V1 token: https://login.microsoftonline.com/{tenant name}/.well-known/openid-configuration

    V2 token: https://login.microsoftonline.com/{tenant name}/v2.0/.well-known/openid-configuration

    For my case, I use the V1 OIDC endpoint. You can either paste the URL into a web browser or postman to find the “jwks_uri” field from the response:

  3. From the JWKS URI endpoint, find the key that has a matching kid (key id) as the token. Copy the long text string from the key’s x5c field. This is the public key section

  4. Enclose the x5c string in the BEGIN CERTIFICATE / END CERTIFICATE block as followed (see example at the end post)

    ‑‑‑‑‑BEGIN CERTIFICATE‑‑‑‑‑

    MIIDBTCCAe2gAwIBAgIQKOfEJNDyDplBSXKYcM6UcjANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE4MTIyMjAwMDAwMFoXDTIwMTIyMjAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK8ZT56lunzbgm3a4QxM8BiVbsd4j77bf/K/rhxyCmuwv2/7seYXsDTEvdUoFD2Tq7Km+eLh4/+yDViqihLRXOGD/NxYbLP7jv5k/e3MxDbOM1mkjfRMMPxc9+sav7meue+dJRysF0CdQP6XvlToDZT4PBAou5nkAydOa/N/HrtY6ShY8ZEK3URUy4GLUUO08V/s80cqEUfIqiXOkb54o4dffmH1rQbAiNa9du0hWpFAa2P2SrCshPSjVlC+x+uRMhUTYCvNF32L4UJRsN/gI39vH4u9cFvgcqStW0wgK88F+84Bdx+j9bvDyqLEjkjf0PfkHPV/kf2Pt2zqTiIizr8CAwEAAaMhMB8wHQYDVR0OBBYEFC//HOy7pEIKtnpMj4bEMA3oJ39uMA0GCSqGSIb3DQEBCwUAA4IBAQAIYxZXIpwUX8HjSKWUMiyQEn0gRizAyqQhC5wdWOFCBIZPJs8efOkGTsBg/hA+X1fvN6htcBbJRfFfDlP/LkLIVNv2zX4clGM20YhY8FQQh9FWs5qchlnP4lSk7UmScxgT3a6FG3OcLToukNoK722Om2yQ1ayWtn9K82hvZl5L3P8zYaG1gbHPGW5VlNXds60jIpcSWLdU2hacYmwz4pPQyvNOW68aK/Y/tWrJ3DKrf1feDbmm7O5kpWVYWRpah+i6ePjELNkc2Jr+2DchBQTIh9Fxe8sz+9iOyLh9tubMJ+7RTs/ksK0sQ1NVScGFxK+o5hFOOMK7y/F5r467jHez

    ‑‑‑‑‑END CERTIFICATE‑‑‑‑‑

  5. Now copy entire text above into the 1st textbox under “Verify Signature” section and the Invalid Signature text should change to “Signature Verified”

 

Conclusion:

The above steps show a manual way to validate the JWT token’s signature given the certificate’s public key.

References:

https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-openid-connect-code

https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc

for clarity:

Example public certificate section

5 dashes followed (no space) by BEGIN CERTIFICATE followed by 5 dashes. The end section is in the same format

-----BEGIN CERTIFICATE-----
MIIC8DCCAdigAwIBAgIQUdK9w17K+rNOSRJZP83bIjANBgkqhkiG9w0BAQsFADA0MTIwMAYDVQQDEylNaWNyb3NvZnQgQXp1cmUgRmVkZXJhdGVkIFNTTyBDZXJ0aWZpY2F0ZTAeFw0xOTA0MTgwMDU5MzNaFw0yMjA0MTgwMDU5MzNaMDQxMjAwBgNVBAMTKU1pY3Jvc29mdCBBenVyZSBGZWRlcmF0ZWQgU1NPIENlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArkGIwWMl5Z6bQDsRZocoylG2Nf91JlBWbGKULJCu8yzoFT5C4JgJ6qoYXjKNIq/+DI8aWsxMclYHmsTRl8JMWaCH1K4BaApYGPYLBjL8DKXm+ELSp9VyAPzD+FYElGCpU+B3FvWcEQvGFBzajhn17J5zutN6I8rGngIK0ewqpekGV85CEFQ5EFwgx7lkF5PLvgiTBq08b8xNB3f0laSGMH7MYjDmGh//Zb2QT/6S7ZzB85YnGtlOxaLjKeYcM8hBdVK5lYqvQb7a0GWmUxmlwClwN3XpBBdg274hBG4ynkWLnx/0Vb5/RfWa0HCRa4JK28sfI/VufdR0SJ+WBZWXZwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA6IpznhiMSBayXGZaw0o8mPtI9qkXaFF5kDLqZFYN1tVTAukG3Q//PPnwsGLdRHFGOn3OwPNwo7XtmM6iyIunKAjTqtf7zA53umWirJzq85l6NVpqtQf7CABOzY3I6NKEa7wmYPBD6Egh6PqJO9O1ppAqJT4z/0lYTIEac7KYMdv/FwpYd0w4Y4gbYtRODO9iQwAXzzM243oM8XSrrqQj3smfNyrZfZS8XWvjQGJy9MTn2Ybvy9IUhVwEWJTyeTKBhnBk9ujNCcEG4kAYL1uWGun+dT2h4vbyNKxMlomryz3actMp90QEefZTZ/kOxqAthenbou+WF0OfhCH9Zhd04
-----END CERTIFICATE-----

Leave a Comment